home *** CD-ROM | disk | FTP | other *** search
/ MacWorld 1998 March / Macworld (1998-03) (Disk 1).dmg / Shareware World / Utilities / Text Processing / Alpha / Tcl / Packages / elecExpansions.tcl < prev    next >
Encoding:
Text File  |  1997-12-02  |  22.5 KB  |  825 lines  |  [TEXT/ALFA]

  1. # Note from Vince: bug reports for this file should go to Tom Fetherston (install)
  2. # (and probably to me too, since I have made some changes)
  3.  
  4. ##===========================================================================
  5. # elecExpansions, formerly acronymExpansions, formerly 'Word-Combinations Completion'
  6.  
  7. # AUTHOR
  8. #    
  9. #    Thomas R. Fetherston
  10. #    Internet: ranch1@earthlink.net
  11. #    USnail:   94 Lipp Ave, Pittsburgh, PA 15229-2001
  12. #
  13. ################################################################################
  14. # HISTORY
  15. #                  
  16. # modified                 who rev reason
  17. # ----------------------   --- --- ------
  18. # 12/2/97                   trf 1.8 made changes to fix TeX expansions
  19. # 05/22/1997               trf 1.7 Removed uses of 'oneSpace', this messed up stop
  20. #                                    locations. 
  21. # 05/14/1997               VD  1.6 Changed proc names to reflect new naming scheme
  22. # 12/30/1996               trf 1.5 Modified so that this could be integrated with 
  23. #                                   Vince Darley's Completion package.
  24. # 07/14/1996 {01:21:20 PM} trf 1.4 Changed previous hit to a list of previous hits
  25. #                                   so hits would be offered only once.
  26. # 07/14/1996 {12:04:37 PM} trf 1.3 work around for regexp to include a close bracket
  27. # 07/12/1996 {12:53:38 AM} trf 1.2 Allow hint to be suffixed with certain puncuation
  28. #                                    marks and still be expanded. Added hint check.
  29. # 07/11/1996 {10:29:51 PM} trf 1.1 Allow expansion of hint prefixed with non-
  30. #                                   alphabetic character(s).
  31. #                                    Ensure Hit used is followed with only one
  32. #                                    space.
  33. # 07/05/1996 {10:28:20 PM} trf 1.0 Original
  34. ################################################################################
  35.  
  36. # Based on wordCompetion.tcl
  37. # Originally composed by Mark Nagata (nagata@kurims.kyoto-u.ac.jp) 
  38. # for Alpha 5.76, 4/22/94.
  39. # Modified by Tim van der Leeuw (tnleeuw@cs.vu.nl), 9/14/94.
  40. # Modified by Tom Fetherston
  41. # All the global variables needed to store state information between calls
  42. # (start with __Gcw_)
  43. #
  44. # This provides a different kind of word completion than the distribution provides, 
  45. # (wordCompletion.tcl).  When you find yourself typing a lot of variable and function 
  46. # names over and over, and these names are word-combinations where the name is formed by 
  47. # either capitalizing each word or separating them with an underscore, just type the 
  48. # initial letter of each word and invoke acronymExpansion instead.  
  49.  
  50. # The idea    of this    modification is    to allow you to    type a string consisting of    the    
  51. # initial letters of the words that    have been joined to make up 
  52. # a variable, function, or    procedure name.    This is    often shorter and more natural than    
  53. # typing a few letter and using wordCompletion. As I developed this routine I found that 
  54. # a regexp for more than three letters caused search to choke so only those letters of a
  55. # "hint" are significant. A three letter pattern is used for the search.  After a possible
  56. # hit is located, it is turned into an acronym and checked against the "hint"
  57. ##
  58. # to do list
  59. # ----------
  60. # change __Gcw_prevHint to a list of previous hits so we only get new hits
  61.  
  62. # monitor the character(s) to the right of the cursor point so the automatic, "oneSapce"
  63. # can be suppressed, e.g. if a comma, close "bracket", or return immediately follows,
  64. # let the inserted text abut it without a space
  65. # cause a hint that ends in an '[' to search for a hit that is
  66. # a parameterized routine. (what is a routine depends on the mode),
  67. # and invoke a "replacement that includes a template for the proper number of arguments
  68.  
  69. # let numerals play a role in finding a "Hit"
  70.  
  71. # let an invocation include a file or list to be searched instead of the current window.
  72. ##
  73. # The string you are going to use expansion on is    entered    in lowercase. The words in    
  74. # the target you are trying to hit have to start with a capital    
  75. # (except the first word), or, be separated    by an underscore.
  76.  
  77. # The hint can be embedded between non-alphabetic characters and certain punctuation marks
  78. # ( '[', '(', '{', ',', ';', ':', ''', '"', ']', ')', '}' ). The expanded hint remains
  79. # so embedded, and the cursor appears one space beyond the trailing punctuation.
  80.  
  81. # e.g. if sin($gl) was expanded, we would get sin($__Gcw_len) (in this file).
  82. # similarly, mouse($gph, would expand to 'mouse($__Gcw_prevHint, ', done twice, we would get
  83. # 'mouse($__Gcw_prevHit, '.
  84. ##,
  85. # The following binding is just a suggestion. It is the one that I like best, I have this
  86. # in my pref.tcl file
  87. # ascii 0x20 <c> bind::Expansion
  88. # i.e. command-<space>
  89.  
  90. #================================================================================
  91.  
  92. alpha::extension elecExpansions 9.0b3 {
  93.     alpha::package require elecBindings 9.0b1
  94.     lunion flagPrefs(Electrics) listPickIfMultExpds
  95.     # similarly for expansions
  96.     newPref flag listPickIfMultExpds 0
  97. } maintainer {
  98.     "Tom Fetherston" "" ""
  99. } uninstall this-file help {file "ElecCompletions Help"}
  100.  
  101. set __Gcw_prevHintPos -1
  102. set __Gcw_prevHint {}
  103. set __Gcw_prevsrcListName {}
  104.  
  105. ensureset __Gcw_already_expanding error
  106. ensureset __Gcw_pos_expanding -1 
  107.  
  108. ## 
  109.  # -------------------------------------------------------------------------
  110.  #     
  111.  #    "bind::Expansion"    --
  112.  #    
  113.  #     If    we're already completing, jump to that procedure, else go through
  114.  #     a mode-dependent list of expansion procedures    given by the array
  115.  #     'completions',    these return either    '1'    to indicate    termination, or
  116.  #     '0' to    say    either that    they failed    or that    they succeeded and that
  117.  #     further expansion    procedures may be applied.
  118.  # -------------------------------------------------------------------------
  119.  ##
  120. proc bind::Expansion {} {
  121.     if ![completion::tabDeleteSelection] return
  122.     
  123.     global __Gcw_already_expanding
  124.     if [elec::notAlreadyExpanding] {
  125.         set __Gcw_already_expanding error
  126.         if [expansion::user] return
  127.         set m [modeALike]
  128.         global expanders
  129.         set curPos [getPos]
  130.         if ![catch {set expandersList $expanders($m)}] {
  131.             foreach e $expandersList {
  132.                 if [completion $m $e] return
  133.             }
  134.         }
  135.         #if none of the expanders succeeded, (or, don't exist) try
  136.         if {([getPos] == $curPos)} {
  137.             expansion::acronym
  138.         }
  139.     }
  140. }
  141.  
  142. ## 
  143.  # -------------------------------------------------------------------------
  144.  #     
  145.  #    "elec::notAlreadyExpanding" --
  146.  #    
  147.  #     Call this to check    if we should divert    directly to    a previously
  148.  #     registered    expansion procedure instead of    starting from scratch.
  149.  # -------------------------------------------------------------------------
  150.  ##
  151. proc elec::notAlreadyExpanding {} {
  152.     global __Gcw_already_expanding __Gcw_pos_expanding
  153.     # do the old expansion if possible
  154.     if { $__Gcw_pos_expanding == [getPos] } {
  155.         return [catch {elec::completion [modeALike] $__Gcw_already_expanding} ]
  156.     } else {
  157.         return 1
  158.     }    
  159. }
  160.  
  161. ## 
  162.  # -------------------------------------------------------------------------
  163.  #     
  164.  #    "elec::alreadyExpanding"    --
  165.  #    
  166.  #     If    a expansion routine has been called once, and would like to
  167.  #     be    called again (to cycle through a number    of possibilities), then
  168.  #     it    should register    itself with    this procedure.
  169.  # -------------------------------------------------------------------------
  170.  ##
  171. proc elec::alreadyExpanding { proc } {
  172.     global __Gcw_already_expanding __Gcw_pos_expanding
  173.     # store the given expansion
  174.     set __Gcw_already_expanding $proc
  175.     set __Gcw_pos_expanding [getPos]
  176. }
  177.  
  178.  
  179. ## 
  180.  # These declare, in order,    the    names of the expander
  181.  # procedures for each mode.  The actual procedure
  182.  # must    be named '${mode}Expansion::${listItem}', unless
  183.  # the item    is 'expansions::*' in which case that actual
  184.  # procedure is    called.
  185.  ##
  186. #===========================================================================
  187.  
  188. set expanders(TeX) {ExCmd}
  189. set expanders(Tcl) {}
  190. set expanders(C) {}
  191.  
  192. # just so we have one!
  193. set userExpansionw(date) {◊kill0◊[lindex [mtime [now]] 0]}
  194.  
  195. proc expansion::user { {cmd ""} } {
  196.     if ![string length $cmd] { set cmd [completion::lastWord] }
  197.     if [containsSpace $cmd] { return 0 }
  198.  
  199.     set curPos [getPos]
  200.  
  201.     elec::findCmd $cmd userExpansionw
  202.     #if the above call resulted in a detectable action, (i.e. the
  203.     # current positon has change), return 1
  204.     if {([getPos] == $curPos)} {
  205.         return 0
  206.     } else {
  207.         return 1
  208.     }
  209. }
  210.  
  211. #    -------------------
  212. proc expansion::acronym {} {
  213.     
  214. global __Gcw_len
  215. global __Gcw_prevHintPos
  216. global __Gcw_prevHint
  217. global __Gcw_endPrevRpl
  218. global __Gcw_prevHits
  219. global __Gcw_patt
  220. global __Gcw_nextStart
  221. global __Gcw_above_BELOW
  222.  
  223. set To [getPos]
  224. set lastChar [lookAt [expr $To - 1]]
  225. set hintCapper [lookAt $To]
  226. switch $hintCapper {
  227.   "\)" -
  228.   "\}" -
  229.   "\]" - 
  230.   " "  -
  231.   "\t" {
  232.     if {$lastChar != ","} {
  233.         set trailingWhite {} 
  234.     } else {
  235.         set trailingWhite " "
  236.     }     
  237.   }
  238.   "default" {
  239.     switch $lastChar {
  240.   "\(" -
  241.   "\{" -
  242.   "\{" - 
  243.   " "  -
  244.   "\t" {
  245.         set trailingWhite {} 
  246.       }
  247.       "default" {
  248.         set trailingWhite " "
  249.       }
  250.     }
  251.     
  252.   }
  253. }
  254.  
  255. backwardWord
  256. set From [getPos]
  257.  
  258. # adjust From to prune any non alphabetic prefix
  259. set hint [getText $From $To]
  260.  
  261. # The following variables may not come into existence in the regexp
  262. #  below, so set up defaults.
  263. set tail ""
  264. set punc ""
  265. #can not seem to include a close brack as below
  266. #regexp {([a-zA-Z_]+)([\(\{\[,;:'"\}\)\]])*[     ]*$} $hint tail hint punc
  267.  
  268. #work around on above
  269. regexp {([a-zA-Z0-9_]+)(([\(\{\[,;:'"\}\)])*(\])*([\(\{\[,;:'"\}\)])*)[     ]*$} $hint tail hint punc
  270. set From [expr $To - [string length $tail]]
  271.  
  272. #   this is a 1stTry, but hint is illegal
  273. if {$From!=$__Gcw_prevHintPos} {
  274.     if {[regexp {[0-9_]} $hint] > 0} {
  275.         alertnote "Ilegal hint, must have only letters in it."
  276.         select $From $To
  277.         set __Gcw_prevHintPos -1
  278.         return
  279.     } elseif {$From==$To} {
  280.         alertnote "Was not able to find any hint."
  281.         set __Gcw_prevHintPos -1
  282.         return
  283.     }
  284. }
  285.  
  286.  
  287. # adjust To, leaving trailing spaces or tabs
  288. set To [expr $From + [string length [append junk $hint $punc]]]
  289.  
  290. # if (Trying to complete a new hint)
  291. if $From!=$__Gcw_prevHintPos {
  292.     set __Gcw_prevHint $hint
  293.     set __Gcw_prevHits {}
  294.     set __Gcw_len [string length $hint]
  295.     set __Gcw_patt  [pFI $hint]
  296.     set __Gcw_above_BELOW 0
  297.     
  298.     set start [expr $From-1]    
  299.     set beg {}; set end {}
  300.     set foundAbove 0
  301.     elec::_searchAboveForHit start   beg end Hit foundAbove
  302.     
  303.     if $foundAbove then {
  304.         lappend __Gcw_prevHits $Hit
  305.         
  306.         # put in the Hit, 
  307.         set replacement {}
  308.         append replacement $Hit $punc $trailingWhite 
  309.         replaceText $From $To $replacement
  310.         goto [expr $From + [string length $replacement]]
  311. #         oneSpace
  312.         
  313.         
  314.         message "found above."
  315.         set __Gcw_prevHintPos $From
  316.  
  317.         set __Gcw_endPrevRpl [getPos]
  318.         elec::_adjustGlobals __Gcw_endPrevRpl  __Gcw_above_BELOW   __Gcw_nextStart
  319.         return
  320.     }
  321.     
  322.     set start $To    
  323.     set beg {}; set end {}
  324.     set __Gcw_above_BELOW 1
  325.     set foundBelow 0
  326.     elec::_searchBelowForHit start   beg end Hit foundBelow
  327.  
  328.     if $foundBelow {
  329.         lappend __Gcw_prevHits $Hit
  330.         
  331.         # put in the Hit, 
  332.         set replacement {}
  333.         append replacement $Hit $punc $trailingWhite 
  334.         replaceText $From $To $replacement
  335.         goto [expr $From + [string length $replacement]]
  336.         
  337.         message "found below."
  338.         set __Gcw_prevHintPos $From
  339.  
  340.         set __Gcw_endPrevRpl [getPos]
  341.         elec::_adjustGlobals __Gcw_endPrevRpl  __Gcw_above_BELOW   __Gcw_nextStart
  342.         return
  343.     }
  344.     
  345.     #No Hit for this hint exists
  346. #     goto $To
  347. #     backwardWordSelect
  348.     select $From $To
  349.     set __Gcw_prevHintPos -1
  350.     return
  351.  
  352. # else: we are re-trying the previous hint
  353. } else {  
  354.     while 1 {
  355.         #pre-set fndMsg, in case there is a valid Hit for this iteration
  356.         if $__Gcw_above_BELOW {
  357.             set fndMsg "found below."
  358.         } else {
  359.             set fndMsg "found above."
  360.         }
  361.  
  362.         set start $__Gcw_nextStart    
  363.         set beg {}; set end {}
  364.         set foundByContinuedSearch 0
  365.         elec::_continueSearchForHit start  beg end Hit foundByContinuedSearch
  366.  
  367.         if $foundByContinuedSearch {            
  368.             #if (this Hit is not the same as the last one)
  369.             if {[lsearch -exact $__Gcw_prevHits $Hit] == -1} {
  370.                 
  371.                 #add the hit to the list of previous hits
  372.                 lappend $__Gcw_prevHits $Hit
  373.                 
  374.                 # put in the Hit, 
  375.                 if {($punc == ",") && [info exists tail]} {
  376.                     set trailingWhite " " 
  377.                 } 
  378.                 # put in the Hit, 
  379.                 set replacement {}
  380.                 append replacement $Hit $punc $trailingWhite 
  381.                 replaceText $From $To $replacement
  382.                 goto [expr $From + [string length $replacement]]
  383.                 
  384.                 message $fndMsg
  385.                 set __Gcw_endPrevRpl [getPos]
  386.                 elec::_adjustGlobals __Gcw_endPrevRpl  __Gcw_above_BELOW   __Gcw_nextStart
  387.                 return
  388.             
  389.             #else: this Hit does not differ from the last
  390.             } else {
  391.                 elec::_adjustGlobals __Gcw_endPrevRpl  __Gcw_above_BELOW   __Gcw_nextStart
  392.                 }
  393.         
  394.         #else: another Hit was not found    
  395.         } else {
  396.             #if (no more Hits can exist, because we have searched all the text)
  397.             if $__Gcw_above_BELOW {
  398.                 message "Not found."
  399. #                 goto $To
  400. #                 backwardWordSelect
  401.                 select $__Gcw_prevHintPos $__Gcw_endPrevRpl
  402.                 set __Gcw_prevHintPos -1
  403.                 return
  404.             #else: we haven't tried BELOW
  405.             } else {
  406.                 set __Gcw_above_BELOW 1
  407.                 set __Gcw_nextStart $__Gcw_endPrevRpl
  408.             }
  409.         }
  410.         
  411.     }
  412.         }
  413. }
  414.  
  415. #    ---
  416. proc pFI wordStarters {
  417.     proc firstPost {char} {
  418.         return [format "(%s|%s)" [string toupper $char] $char ]
  419.     }
  420.     
  421.     proc fencePost {char} {
  422.         return [format {(%1$s|_%1$s|_%2$s)} [string toupper $char] $char ]
  423.     }
  424.     
  425.     set identifierLeader {(_|__)?}
  426.     set wordTail {[a-z0-9]*}
  427.     set identifierTail {[a-zA-Z0-9_]*}
  428.  
  429.     set idx_Last [expr [string length $wordStarters]-1]
  430.     if $idx_Last>2 {set idx_Last 2}
  431.  
  432.     set searchPatt  $identifierLeader
  433.     append searchPatt [firstPost [string index $wordStarters 0]] 
  434.     append searchPatt $wordTail
  435.     
  436.     for {set i 1} {$i < $idx_Last} {incr i} {
  437.         append searchPatt [fencePost [string index $wordStarters $i]]
  438.          append searchPatt $wordTail
  439.     }
  440.     append searchPatt [fencePost [string index $wordStarters $i]]
  441.      append searchPatt $identifierTail
  442.     return $searchPatt
  443. }
  444.  
  445. #Note: in all the following scripts that start with uplevel…, the
  446. # agrguments are "fake", and serve only to show what variables
  447. # are used by these macro-like subroutines.  Their primary purpose
  448. # is to make the above code more readable.  Each is started with
  449. # an underscore to indicate that they are internal to another
  450. # routine, and should not be called by themselves.
  451.  
  452. #    ------------------  -in--  -out--------(bool)-
  453. proc elec::_searchAboveForHit {start  beg end Hit success} {
  454.     
  455. uplevel {
  456.     set BegEnd {-1 -1}
  457.     set moreToSearch 1
  458.     while {$moreToSearch} {
  459.         set foundAbove [expr ![catch {search -s -f 0 -r 1 -i 0 -m 1 -- $__Gcw_patt $start} BegEnd]]
  460.         set beg [lindex $BegEnd 0]
  461.         set end [lindex $BegEnd 1]
  462.         set Hit [getText $beg $end]
  463.         unset BegEnd
  464.         if {!$foundAbove} {break}
  465.         
  466.         set fullMatch [elec::acronymsAreEqual $hint $Hit]
  467.         if {$fullMatch} {
  468.             break
  469.             
  470.         } else {
  471.             set foundAbove 0
  472.         }
  473.         
  474.         if {$beg<=0} {
  475.             set moreToSearch 0
  476.         } else {
  477.             set start [expr $beg-1]
  478.         }
  479.     }
  480. }
  481. }
  482.  
  483. #    ------------------  -in--  -out--------(bool)-
  484. proc elec::_searchBelowForHit {start  beg end Hit success} {
  485.  
  486. uplevel {
  487.     set BegEnd {-1 -1}
  488.     set moreToSearch 1
  489.     while {$moreToSearch} {
  490.         set foundBelow [expr ![catch {search -s -f 1 -r 1 -i 0 -m 1 -- \
  491.           $__Gcw_patt $start} BegEnd]]
  492.         set beg [lindex $BegEnd 0]
  493.         set end [lindex $BegEnd 1]
  494.         set Hit [getText $beg $end]
  495.         unset BegEnd
  496.         if {!$foundBelow} {break}
  497.         
  498.         set fullMatch [elec::acronymsAreEqual $hint $Hit]
  499.         if {$fullMatch} {
  500.             break
  501.             
  502.         } else {
  503.             set foundBelow 0
  504.         }
  505.         
  506.         if {$end>=[maxPos]} {
  507.             set moreToSearch 0
  508.         } else {
  509.             set start [expr $end]
  510.         }
  511.     }
  512. }
  513. }
  514.  
  515. #    ---------------------  -in--  -out--------(bool)-
  516. proc elec::_continueSearchForHit {start  beg end Hit success} {
  517.  
  518. uplevel {
  519.     set BegEnd {-1 -1}
  520.     set moreToSearch 1
  521.     while {$moreToSearch} {
  522.         set foundByContinuedSearch [expr ![catch {search -s -f $__Gcw_above_BELOW -r 1 -i 0 -m 1 -- \
  523.            $__Gcw_patt $__Gcw_nextStart} BegEnd]]
  524.         set beg [lindex $BegEnd 0]
  525.         set end [lindex $BegEnd 1]
  526.         set Hit [getText $beg $end]
  527.         unset BegEnd
  528.         if {!$foundByContinuedSearch} {break}
  529.         
  530.         set fullMatch [elec::acronymsAreEqual $__Gcw_prevHint $Hit]
  531.         if {$fullMatch} {
  532.             break
  533.         } else {
  534.             set foundBelow 0
  535.         }
  536.         
  537.         if {$end>=[maxPos]} {
  538.             set moreToSearch 0
  539.         } else {
  540.             elec::_adjustGlobals __Gcw_endPrevRpl  __Gcw_above_BELOW   __Gcw_nextStart
  541.         }
  542.     }
  543. }
  544. }
  545.  
  546. #    --------------  -in-------------  -mod-------------   -out-----------
  547. proc elec::_adjustGlobals {__Gcw_endPrevRpl  __Gcw_above_BELOW   __Gcw_nextStart} {
  548.     
  549. uplevel {
  550.         if $__Gcw_above_BELOW {
  551.         set __Gcw_nextStart $end
  552.     } else {
  553.         set __Gcw_nextStart [expr $beg - 1]
  554.         if $__Gcw_nextStart<=0 {
  555.             set __Gcw_above_BELOW 1
  556.             set __Gcw_nextStart $__Gcw_endPrevRpl
  557.         }
  558.     }
  559. }
  560. }
  561.  
  562.  
  563.  
  564. #    ----------(bool)  -in- ---------------
  565. proc elec::acronymsAreEqual {hint wordCombination} {
  566.     
  567.  
  568. set splitOnUndrS [split $wordCombination {_}]
  569. set shoe {}
  570. foreach part $splitOnUndrS {
  571.     if {$part == {}} continue
  572.     set part [split $part {}]
  573.     set part [lreplace $part 0 0 [string toupper [lindex $part 0]]]
  574.     set part [join $part {}]
  575.     append shoe $part
  576. }
  577. regsub -all \[a-z0-9\] $shoe {} shoe
  578. return [expr ![string compare [string toupper $hint] $shoe]]
  579. }
  580.  
  581.  
  582. ## 
  583.  # -------------------------------------------------------------------------
  584.  #     
  585.  #    "elec::acronymListExpansions" --
  586.  #    
  587.  #     Given a an acronym of the sub-words in a 'multi-word command' (the 'hint')
  588.  #   and the name of a    list to    search,    that list consisting of 
  589.  #   acronyms-command pairs on separate lines that have been placed in
  590.  #     alphabetical order    and    starting/ending    with a
  591.  #     return, this proc returns a list of all pairs that have the hint as
  592.  #   their first element or'0'    if there were none. 
  593.  #   
  594.  #     Based on Vince Darley's modeListCompletions
  595.  # -------------------------------------------------------------------------
  596.  ##
  597. proc elec::acronymListExpansions { hint dictName } {
  598.     global $dictName
  599.     
  600.     set reg {(\n}
  601.     append reg $hint { +[^\n]+)+}
  602.     if [regexp $reg [set $dictName] pairs] {
  603.          set odd 1
  604.         foreach m $pairs {
  605.              if {$odd % 2 != 0} {
  606.                 incr odd
  607.                  continue
  608.             } 
  609.             incr odd
  610.             append matches $m " "
  611.         }
  612.         return $matches
  613.     } else {
  614.         return 0
  615.     }
  616. }
  617.  
  618. proc elec::expandThis { cmd matches {isdbllist 0} {forcequery 0}} {
  619.     global possMatches returnedMatch listPickIfMultExpds
  620.  
  621.     set possMatches $matches
  622.     set mquery [set match [lindex $matches 0]]
  623.     if $isdbllist { set match [lindex [lindex $match 0] 0]}
  624.     if { [set cmdnum [llength $matches]] == 1 || $match == $cmd } {
  625.         # It's unique or already a command, so insert it 
  626.         backwardDeleteWord
  627.         elec::commandPrefix
  628.         insertText $match
  629.         return $match
  630.     } else {
  631.         set item [lindex $matches [incr cmdnum -1]]
  632.         if $isdbllist { set item [lindex [lindex $item 0] 0] }
  633.         
  634.         set num 1
  635.         set correspondingNum 1
  636.         set numberedChoices "\{"
  637.         set currChoiceSet ""
  638.         set setIdx 0
  639.         set multiSets 0
  640.         set pickNumOfStartIn(0) $correspondingNum
  641.         foreach m $matches {
  642.             append numberedList "\{$num $m\} "
  643.             #make up a list of choiceSets, where eadh choice set has < 79
  644.             # characters
  645.             if {[string length "$currChoiceSet$correspondingNum $m "] < 77} {
  646.                 append numberedChoices "$correspondingNum $m "
  647.                 append currChoiceSet   "$correspondingNum $m "
  648.                 set setAndNum($num) [list $setIdx $correspondingNum]
  649.             } else {
  650.                 incr setIdx
  651.                 set correspondingNum 1
  652.                 append numberedChoices "m…\} \{$correspondingNum $m "
  653.                 set currChoiceSet      "$correspondingNum $m "
  654.                 set setAndNum($num) [list $setIdx $correspondingNum]
  655.                 set pickNumOfStartIn($setIdx) $num
  656.                 set multiSets 1
  657.             }
  658.             incr correspondingNum
  659.             incr num
  660.         }
  661.         if {$multiSets} {
  662.             append numberedChoices "b…\}"
  663.         } else {
  664.             append numberedChoices "\}"
  665.         }
  666.         
  667.         
  668.         
  669.         if { $listPickIfMultExpds } {
  670.             beep
  671.             if [catch { set choice [listpick -p "Pick an expansion" $numberedList]}] {
  672.                 message "Cancelled"
  673.                 return 1
  674.             } else {
  675.                 backwardDeleteWord
  676.                 elec::commandPrefix
  677.                 set choice [lindex $choice 1]
  678.                 insertText $choice
  679.                 return $choice
  680.             }
  681.             
  682.         } else {
  683.             set pickNum 1
  684.             set promptNum $pickNum
  685.             set currChoiceSet_idx 0
  686.             set c "\t"
  687.             backwardDeleteWord
  688.             elec::commandPrefix
  689.             insertText [lindex $matches 0]
  690.             
  691.             while {[set c] == "\t"} {
  692.                 set currChoiceSet_idx [lindex $setAndNum($pickNum) 0]
  693.                 set currChoiceSet     [lindex $numberedChoices $currChoiceSet_idx]
  694.                 #look up what number in the currChoiceSet corresponds to the pickNum
  695.                 set currNum [lindex $setAndNum($pickNum) 1]
  696.                 regsub "$currNum " $currChoiceSet "=>" choices
  697.                 global returnedMatch
  698.                 set returnedMatch ""
  699.                 
  700.                 message $choices
  701.                 set c [getChar]
  702.                 set c [string tolower $c ]
  703.                 scan $c "%c" decRep
  704.                 if {$decRep == 27} {
  705.                     set c "esc"
  706.                 } 
  707.                 switch $c {
  708.                   "\t" {
  709.                       incr pickNum
  710.                       if {$pickNum > [llength $matches]} {
  711.                         set pickNum 1
  712.                     } 
  713.                     backwardDeleteWord
  714.                     elec::commandPrefix
  715.                     insertText [lindex $matches [expr $pickNum -1]]
  716.                     #set things up so we cylce to the next choice
  717.                       continue                      
  718.                   }
  719.                   " " -
  720.                   "\\" -
  721.                   "\r" {
  722.                     #these keys indicate that we are satisfied with the current choice,
  723.                       # just insert the key pressed
  724. #                       alertnote "you pressed a return, \\, or space"
  725. #                       alertnote "pickNum = $pickNum"
  726.                       return [list [lindex $matches [expr $pickNum -1]] $c]
  727.                   }
  728.                   "m" {
  729.                     #when there are more choices than can be diplayed on the statusline
  730.                       # pressing 'm', will get the next set of choices
  731.                       if {[string match "*m…" $currChoiceSet]} {
  732.                         set pickNum $pickNumOfStartIn([expr $currChoiceSet_idx +1])
  733.                     }
  734.                     if {[string match "*b…" $currChoiceSet]} {
  735.                         set pickNum 1
  736.                     } 
  737.                     backwardDeleteWord
  738.                     elec::commandPrefix
  739.                     insertText [lindex $matches [expr $pickNum -1]]
  740.                     #set things up so we cylce to the next choice
  741.                     set c "\t"
  742.                     continue
  743.                   }
  744.                   "b" {
  745.                     #when there are more choices than can be diplayed on the statusline
  746.                       # pressing 'b', will get the first set of choices
  747.                     set pickNum 1
  748.                     set c "\t"
  749.                     backwardDeleteWord
  750.                     elec::commandPrefix
  751.                     insertText [lindex $matches [expr $pickNum -1]]
  752.                     #set things up so we cylce to the next choice
  753.                     continue
  754.                   }
  755.                   "esc" {
  756.                     #when you want to bypass this and get to acronymExpansion
  757.                     backwardDeleteWord
  758.                     insertText $cmd
  759.                     return 0
  760.                   }
  761.                   "default" {
  762.                     #see if c is, or can be converted to, a number in the range 1-9
  763.                     set strPos [string first $c "asdfghjkl123456789"]
  764.                     if {$strPos == -1} {
  765.                         beep
  766.                         return
  767.                     }
  768.                     set numberChoosen [expr $strPos % 9]
  769.                     if {$numberChoosen > [llength $possMatches]} {
  770.                         beep
  771.                         return
  772.                     } 
  773.                     #alertnote "you choose number $numberChoosen"    
  774.                     set returnedMatch [lindex $possMatches [expr $pickNumOfStartIn($currChoiceSet_idx) + $numberChoosen -1]]
  775.                     
  776.                     
  777.                   }
  778.                 }
  779.     #             catch {statusPrompt -f $choices statusLineChooser}
  780.                 if {$returnedMatch != ""} {
  781.                     backwardDeleteWord
  782.                     elec::commandPrefix
  783.                     insertText $returnedMatch
  784.                     return $returnedMatch                
  785.                 } 
  786.                 
  787.             }
  788.                 
  789.             }
  790.             
  791.         return ""
  792.     }
  793.     
  794.     
  795. }
  796.  
  797.  
  798.  
  799. proc elec::commandPrefix {} {
  800.     global mode
  801.     
  802.     switch $mode {
  803.       "TeX" {
  804.         set pos [getPos]
  805.         set bol [getText [lineStart $pos] $pos]
  806.           switch -glob $bol {
  807.           "*\\begin\{" -
  808.           "*\\end\{" - 
  809.           "*\\" {
  810.             return
  811.           }
  812.           "default" {
  813.             insertText "\\"
  814.           }
  815.         }
  816.       }
  817.     }
  818. }
  819.                     
  820.